从一个 struct 到一个 抽象数据类型(ADT) 标志着从一个“透明盒”(每个内部连接都暴露在外)转变为一个“黑箱”,其中 接口 与 实现分离。这种转变确保了 封装:用户通过调用如 read 或 combine 等函数进行交互,而无需了解收入是如何计算或存储的。
1. 类架构
每个类都定义了一个 唯一类型标识。即使两个类具有完全相同的成员,C++ 也认为它们是不兼容的。使用 typedef 和 前向声明 (例如, class Screen;)使我们能够在保持抽象性的同时设计复杂的关系。我们通常使用 合成版本 的构造函数,例如 Sales_data() = default;,以保持内置类型的便利性($$total = trans;$$)。
2. 非成员接口函数
像 read 这样的函数是 非成员类相关函数。它们属于接口的一部分,但不属于类本身,通常需要 友元关系 来访问私有数据。
main.py
TERMINALbash — 80x24
> Ready. Click "Run" to execute.
>
QUESTION 1
What is the result of the following code?
struct First { int i; }; struct Second { int i; }; First f; Second s = f;Success: The members are identical.
Error: obj1 and obj2 have different types.
Success: C++ allows structural typing.
Warning: members should be private.
✅ Correct!
In C++, even if members are identical, each class/struct definition creates a unique type identity.❌ Incorrect
Class uniqueness is a fundamental rule; type names matter, not just the contents.QUESTION 2
Which keyword is used to request the compiler to generate a synthesized default constructor?
= auto= synthesized= default= virtual✅ Correct!
= default can appear with the declaration inside the class or the definition outside.❌ Incorrect
The specific syntax introduced in C++11 is = default.QUESTION 3
Why is the
read function typically not a member of the Sales_data class?It requires access to private members.
Member functions cannot return stream references.
IO operations are often conceptually separate from the object's core state logic.
Nonmember functions are faster.
✅ Correct!
Nonmember functions like read and print are part of the interface but kept separate to maintain logical cohesion.❌ Incorrect
While it may need friendship to access private data, the separation is an architectural choice.QUESTION 4
What is the default access level for a
class vs a struct in C++?Both are private by default.
class: private; struct: public.
class: public; struct: private.
Both are public by default.
✅ Correct!
The only technical difference between class and struct is the default access level for members and inheritance.❌ Incorrect
Think of struct as 'data-first' (public) and class as 'logic-first' (private).QUESTION 5
What does a 'forward declaration' like
class Screen; allow you to do?Define the full body of the class later.
Allocate an object of type Screen immediately.
Access the private members of Screen.
Inline all Screen member functions.
✅ Correct!
It introduces the name as an incomplete type, allowing you to define pointers or references to it before the full definition.❌ Incorrect
You cannot instantiate an incomplete type (size is unknown) until it is defined.Architecting the Sales_data Interface
Applying Interface/Implementation Separation
You are tasked with upgrading a legacy struct-based system to a formal ADT. You must implement the standard interface functions while strictly hiding implementation details.
Q
1. Provide the code for Exercise 7.6: Define your own versions of the add, read, and print functions for Sales_data.
Solution:
istream &read(istream &is, Sales_data &item) { double price = 0; is >> item.bookNo >> item.units_sold >> price; item.revenue = price * item.units_sold; return is; }ostream &print(ostream &os, const Sales_data &item) { os << item.isbn() << " " << item.units_sold << " " << item.revenue; return os; }Sales_data add(const Sales_data &lhs, const Sales_data &rhs) { Sales_data sum = lhs; sum.combine(rhs); return sum; }Q
2. In your Person class (Exercise 7.19), which members should be public and which private? Explain.
Solution:
Data members like
Data members like
string name; and string address; should be private to prevent direct tampering. The public interface should include constructors and 'getter' functions like getName() and getAddress(). This allows the internal storage (e.g., changing string to a custom Name object) to change without breaking user code.Q
3. If a Screen function like
set returns Screen (by value) instead of Screen& (by reference), what happens to the chain myScreen.move(4,0).set('#');?Solution:
The
The
move function returns a temporary copy of myScreen. The subsequent set('#') is called on this temporary copy, not the original myScreen object. Consequently, the original myScreen remains unchanged after the move.